package com.cxyd.modules.wms.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cxyd.common.page.PageData;
import com.cxyd.common.exception.RootException;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.common.utils.ConvertUtils;
import com.cxyd.common.utils.ProcResult;
import com.cxyd.common.utils.Result;
import com.cxyd.modules.security.user.SecurityUser;
import com.cxyd.modules.sys.dto.SysUserDTO;
import com.cxyd.modules.sys.service.SysUserService;
import com.cxyd.modules.wms.dao.OrderDetailDao;
import com.cxyd.modules.wms.dao.StockDao;
import com.cxyd.modules.wms.dto.AllotRecordDTO;
import com.cxyd.modules.wms.dto.AllotTempDTO;
import com.cxyd.modules.wms.dto.OrderDetailDTO;
import com.cxyd.modules.wms.entity.AllotRecordEntity;
import com.cxyd.modules.wms.entity.AllotTempEntity;
import com.cxyd.modules.wms.entity.OrderDetailEntity;
import com.cxyd.modules.wms.entity.StockEntity;
import com.cxyd.modules.wms.service.AllotTempService;
import com.cxyd.modules.wms.service.OrderDetailService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;

/**
 * 出库明细
 *
 * @author g_Cycle gengruyi01@163.com
 * @since 1.0.0 2023-04-27
 */
@Slf4j
@Service
public class OrderDetailServiceImpl extends CrudServiceImpl<OrderDetailDao, OrderDetailEntity, OrderDetailDTO> implements OrderDetailService {
    private final AllotTempService allotTempService;
    private final SysUserService userService;
    private final StockDao stockDao;

    public OrderDetailServiceImpl(SysUserService userService, AllotTempService allotTempService, StockDao stockDao) {
        this.userService = userService;
        this.allotTempService = allotTempService;
        this.stockDao = stockDao;
    }

    @Override
    public PageData<OrderDetailDTO> page(Map<String, Object> params) {
        //1.查询主单信息
        final IPage<OrderDetailEntity> page = baseDao.selectPage(
                getPage(params, "create_date", false),
                getWrapper(params)
        );

        //2.获取用户信息
        final List<SysUserDTO> userList = userService.getList();
        //3.将creator与updater的username通过id进行绑定
        page.getRecords().forEach(entity -> {
            if (entity.getCreator() != null) {
                entity.setCreatorName(userService.getUsernameById(entity.getCreator(), userList));

            }
            if (entity.getUpdater() != null) {
                entity.setUpdaterName(userService.getUsernameById(entity.getUpdater(), userList));
            }

            //按reelid显示数量 2025-1-2
            String reelId = entity.getReelId();
            if (reelId != null) {
                try {
                    BigDecimal stockQty = stockDao.selectOne(new QueryWrapper<StockEntity>()
                            .eq("reel_id", reelId)
                            .last(" limit 1 ")).getStockQty();
                    entity.setStockQty(stockQty);
                } catch (Exception ex) {
                    entity.setStockQty(BigDecimal.ZERO);

                }

                entity.setLackQty(BigDecimal.ZERO);

            } else {
                String spuNo = entity.getSpuNo();
                String positionType = entity.getLocate();
                String stockType = entity.getStockType();
                BigDecimal stockQty = stockDao.getStockQtySumBySpu(spuNo, positionType, stockType);
                entity.setStockQty(stockQty);
                BigDecimal chaQty = entity.getPlanQty().subtract(entity.getBindQty());
                BigDecimal lackQty = chaQty.compareTo(BigDecimal.ZERO)
                        > 0 ? chaQty.subtract(stockQty) : BigDecimal.ZERO;
                lackQty = lackQty.compareTo(BigDecimal.ZERO) > 0 ? lackQty : BigDecimal.ZERO;
                entity.setLackQty(lackQty);
            }

        });
        return getPageData(page, OrderDetailDTO.class);
    }

    @Override
    public QueryWrapper<OrderDetailEntity> getWrapper(Map<String, Object> params) {
        Long orderId = ObjectUtils.isNotEmpty(params.get("orderId")) ? Long.parseLong((String) params.get("orderId")) : null;
        Long detailId = ObjectUtils.isNotEmpty(params.get("detailId")) ? Long.parseLong((String) params.get("detailId")) : null;
        String spuNo = (String) params.get("spuNo");
        String spuName = (String) params.get("spuName");
        String zllbh = (String) params.get("zllbh");
        String locate = (String) params.get("locate");
        String stockType = (String) params.get("stockType");
        Integer detailSt = ObjectUtils.isNotEmpty(params.get("detailSt")) ? Integer.parseInt((String) params.get("detailSt")) : null;

        QueryWrapper<OrderDetailEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(ObjectUtils.isNotEmpty(orderId), "order_id", orderId);
        wrapper.eq(ObjectUtils.isNotEmpty(detailId), "detail_id", detailId);
        wrapper.eq(ObjectUtils.isNotEmpty(detailSt), "detail_st", detailSt);
        wrapper.eq(ObjectUtils.isNotEmpty(stockType), "stock_type", stockType);
        wrapper.like(StringUtils.isNotBlank(spuNo), "spu_no", spuNo);
        wrapper.like(StringUtils.isNotBlank(spuName), "spu_name", spuName);
        wrapper.like(StringUtils.isNotBlank(zllbh), "zllbh", zllbh);
        wrapper.like(StringUtils.isNotBlank(locate), "locate", locate);
        wrapper.orderByDesc("create_date");
        wrapper.orderByAsc("zllbh");
        return wrapper;
    }

    @Override
    public ProcResult procDetailAutoAllot(Map<String, Object> params) {
        //业务逻辑...
        baseDao.procOrderDetailAllotAuto(params);
        final String code = (String) params.get("code");
        final String msg = (String) params.get("msg");
        return new ProcResult().result(code, msg);
    }

    @Override
    public ProcResult procDetailManualExec(Map<String, Object> params) {
        baseDao.procOrderDetailAllotExec(params);
        final String code = (String) params.get("code");
        final String msg = (String) params.get("msg");
        return new ProcResult().result(code, msg);
    }

    @Override
    public ProcResult procDetailBatchExec(Long[] ids, Long userId) {
        int successQty = 0;
        int errorQty = 0;
        Map<String, Object> map = new HashMap<>();
        map.put("userId", userId);
        if (ids.length > 6) {
            return new ProcResult().result("500", "批量执行数量过多!请控制在[5]条以下");
        }
        for (Long id : ids) {
            map.put("detailId", id);
            baseDao.procOrderDetailAllotExec(map);
            String code = (String) map.get("code");
            if ("0".equals(code)) {
                successQty += 1;
            } else {
                errorQty += 1;
            }
            log.info("执行结果:{}", map.get("msg"));
        }
        //判断批量执行完成情况
        if (successQty > 0 && errorQty == 0) {
            return new ProcResult().result("0", "批量出库执行[全部]成功!");
        } else if (successQty > 0 && errorQty > 0) {
            return new ProcResult().result("0", "批量出库执行[部分]成功!详情可查阅日志");
        } else {
            return new ProcResult().result("500", "批量出库执行[全部]失败!详情可查阅日志");
        }
    }

    @Override
    public ProcResult procDetailRefund(Map<String, Object> params) {
        baseDao.procOrderDetailRefund(params);
        final String code = (String) params.get("code");
        final String msg = (String) params.get("msg");
        return new ProcResult().result(code, msg);
    }

    @Override
    public ProcResult procDetailManualAllot(List<AllotTempDTO> dtoList) {
        if (dtoList.isEmpty()) {
            return null;
        }
        //获取uid
        UUID uuid = UUID.randomUUID();
        //将数据批量新增至[wms_allot_temp]表中
        List<AllotTempEntity> entities = ConvertUtils.sourceToTarget(dtoList, AllotTempEntity.class);
        entities.stream().forEach(item -> item.setUid(uuid.toString()));
        allotTempService.insertBatch(entities);
        //调用存储过程处理手工配货
        Map<String, Object> params = new HashMap<>();
        params.put("uuid", uuid);
        baseDao.procOrderDetailAllotManual(params);
        final String code = (String) params.get("code");
        final String msg = (String) params.get("msg");
        return new ProcResult().result(code, msg);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result procDetailImport(MultipartFile file) {
        //出库单导入库
        //更新版本，2025-1-2 1-导入时生成波次号，出库时，一个波次一起出 2.导入仅有REELID的字段的批量出库
        Long userId = SecurityUser.getUser().getId();
        Date now = new Date();
        Result result = new Result();

        //生成波次
        String waveNo = UUID.randomUUID().toString().replace("-", "");
        try (InputStream in = file.getInputStream()) {
            // 将读取到的Excel内容转为List，接下来只需要对数据执行需要的操作
            List<OrderDetailEntity> list = EasyExcel.read(in).head(OrderDetailEntity.class).sheet().doReadSync();
            List<OrderDetailEntity> insertList = new ArrayList<>();
            for (OrderDetailEntity obj : list) {
                obj.setCreateDate(now);

                obj.setCreator(userId);
                obj.setUpdater(userId);
                obj.setDetailSt(0);

                obj.setWaveNo(waveNo);

                //校验字段的值有无
                if (obj.getReelId() == null) {
                    if (obj.getZllbh() == null) {
                        throw new Exception("工單號不能爲空");
                    }
                    if (obj.getLocate() == null) {
                        throw new Exception("庫別不能爲空");
                    }
                    if (obj.getStockType() == null) {
                        throw new Exception("倉庫分類不能爲空");
                    }
                    if (obj.getPlanQty() == null) {
                        throw new Exception("數量不能爲空");
                    }
                    if (obj.getSpuNo() == null) {
                        throw new Exception("料號不能爲空");
                    }
                    if (baseDao.exists(new QueryWrapper<OrderDetailEntity>()
                            .eq("zllbh", obj.getZllbh()))) {
                        throw new Exception("工单【" + obj.getZllbh() + "】数据已导入，不允许重复");
                    }
                    obj.setComments("原数量:" + obj.getPlanQty().toString() + ";");
                    if (insertList.stream().count() > 0) {
                        //查看有没有相同物料，进行合并
                        for (OrderDetailEntity insertObj : insertList) {
                            if (insertObj.getSpuNo().equals(obj.getSpuNo())
                                    && insertObj.getLocate().equals(obj.getLocate())
                                    && insertObj.getStockType().equals(obj.getStockType())
                                    && insertObj.getPlanQty().compareTo(BigDecimal.ZERO) > 0
                                    && insertObj.getDetailSt() == 0) {
                                insertObj.setPlanQty(insertObj.getPlanQty().add(obj.getPlanQty()));//合并计划数量
                                insertObj.setComments(insertObj.getComments() + obj.getZllbh() + "," + obj.getPlanQty().toString() + ";");//备注

                                obj.setComments(obj.getComments() + "合并工单：" + insertObj.getZllbh() + ";");
                                obj.setPlanQty(BigDecimal.ZERO);//计划数量赋值0
                                obj.setDetailSt(2);//直接完成
                                break;
                            }

                        }

                    }
                } else {
                    obj.setPlanQty(BigDecimal.ZERO);//计划数量赋值0
                }

                Date now2 = new Date();//更新时间
                obj.setUpdateDate(now2);

                insertList.add(obj);
            }
            int count = baseDao.batchSaveOrderDetails(list);
            result.setCode(0);
            result.setMsg("成功导入" + count + "条出库单");
        } catch (Exception ex) {
            result.setCode(-1);
            result.setMsg(ex.getMessage());
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(OrderDetailDTO dto) {
        OrderDetailEntity entity = ConvertUtils.sourceToTarget(dto, OrderDetailEntity.class);

        insert(entity);
    }

    @Override
    public int batchSave(List<OrderDetailEntity> details) {
        return baseDao.batchSaveOrderDetails(details);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(OrderDetailDTO dto) {
        OrderDetailEntity entity = ConvertUtils.sourceToTarget(dto, OrderDetailEntity.class);
        //明细单状态必须为初始状态
        if (entity.getDetailSt() != 0) {
            throw new RootException("只有[初始]状态明细单才可以修改数量");
        }
        updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(@RequestBody Long[] ids) {
        for (int i = 0; i < ids.length; i++) {
            deleteDetailById(ids[i]);
        }
    }

    @Override
    public List<OrderDetailDTO> getList(Map<String, Object> params) {
        List<OrderDetailEntity> entityList = baseDao.selectList(
                getWrapper(params)
        );
        //2.获取用户列表
        final List<SysUserDTO> userList = userService.getList();
        //3.将creator与updater的username通过id进行绑定
        entityList.forEach(entity -> {
            if (entity.getCreator() != null) {
                entity.setCreatorName(userService.getUsernameById(entity.getCreator(), userList));
            }
            if (entity.getUpdater() != null) {
                entity.setUpdaterName(userService.getUsernameById(entity.getUpdater(), userList));
            }
        });
        return ConvertUtils.sourceToTarget(entityList, OrderDetailDTO.class);
    }

    public void deleteDetailById(Long id) {
        OrderDetailEntity entity = baseDao.selectById(id);
        //判断明细状态是否为初始状态
        if (entity.getDetailSt() != 0) {
            throw new RootException("只有[初始]状态明细单才可以删除");
        }
        //删除
        baseDao.deleteById(id);
    }
}